package com.seguriapp.services.web;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.seguriapp.entities.MediaContentType;
import com.seguriapp.services.ComplaintService;
import com.seguriapp.util.Util;

/**
 * Servlet that handles file uploads
 * 
 * @author Tania Gonzales (taniadgv@gmail.com)
 */
public class CommonsFileUploadServlet extends HttpServlet {

  private static final long serialVersionUID = 1L;
  public static final String REDIRECT_URL = "/home/complaint/mediaContentUploaded/";
  private static final String TMP_DIR_PATH = "/usuarios/seguriapp/uploaded";
  // private static final String TMP_DIR_PATH = "C:\\test";
  private File tmpDir;
  public static final String DESTINATION_DIR_PATH = "/usuarios/seguriapp/uploaded";
  // public static final String DESTINATION_DIR_PATH = "C:\\test";
  private File destinationDir;

  public static final int FILE_SIZE = 1024;
  public static final int FILE_NAME_SIZE = 16;
  public static final String FILE_TYPE = "type";
  public static final String COMPLAINT_ID = "complaintId";
  public static final String UPLOAD_TYPE = "uploadType";
  private static final String SUCCESS_TRUE = "success: true";
  private static final String SUCCESS_FALSE = "{success: false}";
  private static final String FILE_NAME_TEMPLATE = "%s-%s-%s";

  private static final Logger LOGGER = Logger.getLogger(CommonsFileUploadServlet.class);

  /**
   * {@inheritDoc}
   * 
   * @param config
   * @throws ServletException
   */
  @Override
  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    tmpDir = new File(TMP_DIR_PATH);
    if (!tmpDir.isDirectory()) {
      throw new ServletException(TMP_DIR_PATH + " is not a directory");
    }
    destinationDir = new File(DESTINATION_DIR_PATH);
    if (!destinationDir.isDirectory()) {
      throw new ServletException(DESTINATION_DIR_PATH + " is not a directory");
    }
  }

  /**
   * Handles the HTTP <code>POST</code> method.
   * 
   * @param request
   *          servlet request
   * @param response
   *          servlet response
   * @throws ServletException
   *           if a servlet-specific error occurs
   * @throws IOException
   *           if an I/O error occurs
   */
  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException {
    LOGGER.info("========U P L O A D ============");
    PrintWriter writer = null;
    InputStream is = null;
    FileOutputStream fos = null;
    response.setContentType("text/plain");
    try {
      writer = response.getWriter();
    } catch (IOException ex) {
      log(CommonsFileUploadServlet.class.getName() + "has thrown an exception: " + ex.getMessage());
    }

    String filename = request.getHeader("X-File-Name") == null ? request.getParameter("qqfile") : request.getHeader("X-File-Name");
    try {
      if (ServletFileUpload.isMultipartContent(request)) {
        String responseStr = uploadFileFromForm(request, response, filename);
        response.setStatus(HttpServletResponse.SC_OK);
        writer.print(responseStr);
      } else {
        is = request.getInputStream();
        fos = new FileOutputStream(new File(String.format("%s/%s", DESTINATION_DIR_PATH, filename)));
        IOUtils.copy(is, fos);
        response.setStatus(HttpServletResponse.SC_OK);
        writer.print("{" + SUCCESS_TRUE + "}");
      }
    } catch (FileNotFoundException ex) {
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      writer.print(SUCCESS_FALSE);
      LOGGER.error("Error encountered while parsing the request", ex);
    } catch (IOException ex) {
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      writer.print(SUCCESS_FALSE);
      LOGGER.error("Error encountered while parsing the request", ex);
    } catch (Exception ex) {
      response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
      writer.print(SUCCESS_FALSE);
      LOGGER.error("Error encountered while parsing the request", ex);
    } finally {
      try {
        if (fos != null) {
          fos.close();
        }
        if (is != null) {
          is.close();
        }
      } catch (IOException ignored) {
      }
    }

    // writer.flush();
    writer.close();
  }

  @SuppressWarnings("rawtypes")
  private String uploadFileFromForm(HttpServletRequest request, HttpServletResponse response, String filename) throws IOException {
    String responseStr = null;
    response.setContentType("text/plain");
    DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
    /*
     * Set the size threshold, above which content will be stored on disk.
     */
    fileItemFactory.setSizeThreshold(1 * FILE_SIZE * FILE_SIZE); // 1 MB
    /*
     * Set the temporary directory to store the uploaded files of size above
     * threshold.
     */
    fileItemFactory.setRepository(tmpDir);

    ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
    try {
      /*
       * Parse the request
       */
      List items = uploadHandler.parseRequest(request);
      Iterator itr = items.iterator();

      FileItem uploadedItem = null;
      FileItem item;
      final String fileType = request.getHeader(FILE_TYPE);
      final String complaintId = request.getHeader(COMPLAINT_ID);
      while (itr.hasNext()) {
        item = (FileItem) itr.next();
        if (!item.isFormField()) {
          uploadedItem = item;
        }
      }
      /*
       * Write file to the ultimate location.
       */
      if (uploadedItem != null) {
        LOGGER.info("Upload File: complaintId = " + complaintId + " fileType = " + fileType + " fileName = " + uploadedItem.getName());
        if (!destinationDir.exists()) {
          destinationDir.mkdirs();
        }
        File tempFile = destinationDir;
        if (MediaContentType.Image.name().equals(fileType)) {
          tempFile = new File(destinationDir + Util.IMAGES_DIR);
        } else if (MediaContentType.Audio.name().equals(fileType)) {
          tempFile = new File(destinationDir + Util.AUDIOS_DIR);
        } else if (MediaContentType.Video.name().equals(fileType)) {
          tempFile = new File(destinationDir + Util.VIDEOS_DIR);
        }
        if (tempFile != null) {
          if (!tempFile.exists()) {
            tempFile.mkdirs();
          }
          final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmssSS");
          final int pos = uploadedItem.getName().lastIndexOf(".");
          final String fileName = String.format(FILE_NAME_TEMPLATE, complaintId, uploadedItem.getName().substring(0, pos),
              dateFormat.format(new Date(System.currentTimeMillis())));
          final String fileExt = uploadedItem.getName().substring(pos).toLowerCase();
          final File file = new File(tempFile, fileName.concat(fileExt));
          uploadedItem.write(file);
          LOGGER.info("ITEM UPLOADED: " + file.getName());
          final WebApplicationContext springContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
          final ComplaintService complaintService = (ComplaintService) springContext.getBean("complaintServiceImpl");
          complaintService.saveMediaContent(Long.valueOf(complaintId), fileType, file.getName());
        }
      }
    } catch (FileUploadException ex) {
      LOGGER.error("Error encountered while uploading file", ex);
    } catch (Exception ex) {
      LOGGER.error("Error encountered while uploading file", ex);
    }
    return responseStr;
  }
}
